<!--
> Muaz Khan     - wwww.MuazKhan.com
> MIT License   - www.WebRTC-Experiment.com/licence
> Documentation - github.com/muaz-khan/WebRTC-Experiment/tree/master/WebRTC-File-Sharing
-->
<html>
    <head>
        <script>
            if(!location.hash.replace('#', '').length) {
                location.href = location.href.split('#')[0] + '#' + (Math.random() * 100).toString().replace('.', '');
                location.reload();
            }
        </script>

        <title>WebRTC File Sharing using SCTP Data Channels | Muaz Khan</title>
        <meta name="description" content="WebRTC File Sharing Experiment using WebRTC SCTP based DataChannel API.">
        <meta name="keywords" content="WebRTC,Experiments,SCTP,DataChannel,File-Sharing">
        <link rel="author" type="text/html" href="http://google.com/+MuazKhan">
        <meta name="author" content="Muaz Khan">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">

        <style type='text/css'>
            @font-face {
                font-family: 'Myriad';
                src: url('https://www.webrtc-experiment.com/fonts/MyriadPro-Light.otf') format("opentype");
                font-weight: 400;
            }

            * { -webkit-user-select: none; }

            body {
                background: #474747 url('');
                color: #777;
                cursor: default;
                font-family: Myriad, Arial, Verdana;
                font-size: 19px;
                margin: 0 auto;
                text-align: center;
            }

            hr { border-color: #777; }

            a {
                color: #888;
                text-decoration: none;
                text-shadow: 0 1px #333;
            }

            p a:hover { color: #6792cc; }

            #blah {
                font-size: 2em;
                line-height: 30px;
                margin-top: 128px;
            }

            .canary:hover { color: #e6c11e; }

            .button {
                background-color: rgba(0, 0, 0, .3);
                border-bottom: 1px solid #666;
                border-radius: 4px;
                box-shadow: inset 0 2px 2px #111;
                cursor: pointer;
                font-size: 22px;
                margin: 0 auto;
                margin-top: 64px;
                overflow: hidden;
                padding: 8px;
                position: relative;
                width: 324px;
            }

            @-webkit-keyframes woohoo {
            0%,

            100% { opacity: .5; } 
            50%

             { opacity: 1; }

            }

            .button span {
                -webkit-animation: woohoo 2s infinite;
				margin: 0 .2em;
            }

            .button span:nth-child(2) {
                color: #6792cc;
            }

            .rotate {
                -webkit-transform: rotate(360deg);
                   -moz-transform: rotate(360deg);
                    -ms-transform: rotate(360deg);
                     -o-transform: rotate(360deg);
                        transform: rotate(360deg);

                -webkit-transition: all 0.6s ease-out;
                   -moz-transition: all 0.6s ease-out;
                    -ms-transition: all 0.6s ease-out;
                     -o-transition: all 0.6s ease-out;
                        transition: all 0.6s ease-out;
            }

            #social {
                margin-top: 60px;
                opacity: 0;
            }

            #social.displayed {
                opacity: 1;
                -webkit-transition: all 0.8s ease-out;
                   -moz-transition: all 0.8s ease-out;
                    -ms-transition: all 0.8s ease-out;
                     -o-transition: all 0.8s ease-out;
                        transition: all 0.8s ease-out;
            }

            #sorry {
                margin-top: 64px;
                color: #9ACD32;
            }

            .credits {
                font-size: 70%;
                opacity: 0.6;
            }
			
			audio, video {
				width: 40%;
				vertical-align:top;
			}
			
			ol li {
				border-top: 8px solid rgb(0, 0, 0);
				list-style:none;
			}
			ol li a {
				color:red;
			}
			
			footer {
				position:fixed;
				bottom:0;
				left:0;
				right:0;
				border-top:1px solid #777;
				background: inherit;
			}
        </style>
        <style>
            * {
                margin: 0;
                padding: 0;
            }

            .output-panel {
                max-height: 80%;
                overflow: hidden;
            }
        </style>
        <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
        <script src="File.js"></script>
        <script src="https://www.webrtc-experiment.com/IceServersHandler.js"></script><!-- required -->
        <script src="PeerConnection.js"></script>
    </head>
    <body>
        <p id="blah">WebRTC File Sharing using SCTP Data Channels</p>
        
        <div class="button" id="setup-offer">
            <span>Setup</span><span>WebRTC Connection</span>
        </div>
		
        <div class="button" style="padding: 0;">
            <input type="file" id="file" disabled style="font-size: 2em;">
            <ol id="users-list"></ol>
            <ol class="output-panel"></ol>
        </div>
        
        <footer>
            <p>
                Want to share files privately?
				
                <a href="#1877571462" target="_blank" 
                   title="Open this link in new tab to share files privately!">
                    <code>
                        <strong id="unique-token">#1877571462</strong>
                    </code>
                </a>
                &rarr;
                <a href="https://www.webrtc-experiment.com/">https://www.webrtc-experiment.com/</a>
            </p>
        </footer>


        <script>
            var progressHelper = { };
            var outputPanel = document.querySelector('.output-panel');

            var fileHelper = {
                onBegin: function(file) {
                    var li = document.createElement('li');
                    li.title = file.name;
                    li.style.textAlign = 'left';
                    li.innerHTML = file.name + '<br><label>0%</label> <progress></progress><div id="size-remaining">' + bytesToSize(file.size || 0) + '<hr><div id="chunks-remaining">0/'+file.maxChunks+'</div></div>';
                    outputPanel.insertBefore(li, outputPanel.firstChild);
                    progressHelper[file.uuid] = {
                        li: li,
                        progress: li.querySelector('progress'),
                        label: li.querySelector('label'),
                        chunks_remaining: li.querySelector('#chunks-remaining'),
                        size_remaining: li.querySelector('#size-remaining'),
                        size: file.size,
                        name: file.name
                    };
                    progressHelper[file.uuid].progress.max = file.maxChunks;
                },
                onEnd: function(file) {
                    progressHelper[file.uuid].li.innerHTML = getFileHTML(file);
                },
                onProgress: function(chunk) {
                    var helper = progressHelper[chunk.uuid];
                    helper.progress.value = chunk.currentPosition || chunk.maxChunks || helper.progress.max;
                    helper.chunks_remaining.innerHTML = (chunk.currentPosition || 0) + '/' + (chunk.maxChunks || helper.progress.max) + ' pieces';
                    helper.size_remaining.innerHTML = bytesToSize(chunk.size * chunk.currentPosition || 0) + (chunk.sending ? ' sent ' : ' received ') + 'out of ' + bytesToSize(helper.size);
                    updateLabel(helper.progress, helper.label);
                }
            };

            function getFileHTML(file) {
                var url = file.url || URL.createObjectURL(file);
                var attachment = '<a href="' + url + '" target="_blank" download="' + file.name + '">Download: <b>' + file.name + '</b></a>';
                if (file.name.match(/\.jpg|\.png|\.jpeg|\.gif/gi)) {
                    attachment += '<br><img crossOrigin="anonymous" src="' + url + '" style="max-width:100%;">';
                } else if (file.name.match(/\.wav|\.mp3/gi)) {
                    attachment += '<br><audio src="' + url + '" controls></audio>';
                } else if (file.name.match(/\.pdf|\.js|\.txt|\.sh/gi)) {
                    attachment += '<iframe class="inline-iframe" src="' + url + '"></iframe></a>';
                }
                return attachment;
            }

            function bytesToSize(bytes) {
                var k = 1000;
                var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
                if (bytes === 0) {
                    return '0 Bytes';
                }
                var i = parseInt(Math.floor(Math.log(bytes) / Math.log(k)), 10);
                return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i];
            }

            document.querySelector('input[type=file]').onchange = function() {
                var file = this.files[0];
                File.Send({
                    file: file,
                    channel: peerConnection,
                    interval: 100,
                    onBegin: fileHelper.onBegin,
                    onEnd: fileHelper.onEnd,
                    onProgress: fileHelper.onProgress
                });
            };

            // --------------------------------------------------------
            var receiver = new File.Receiver(fileHelper);

            // --------------------------------------------------------

            function updateLabel(progress, label) {
                if (progress.position == -1) return;
                var position = +progress.position.toFixed(2).split('.')[1] || 100;
                label.innerHTML = position + '%';
            }

            // --------------------------------------------------------
            var setupOffer = document.getElementById('setup-offer'),
                innerHTML;
            setupOffer.onclick = function() {
                if (setupOffer.className.indexOf('disabled') != -1) {
                    innerHTML = setupOffer.innerHTML;
                    setupOffer.innerHTML = "Don't Click!";
                    setTimeout(function() {
                        setupOffer.innerHTML = innerHTML;
                    }, 500);
                    return;
                }

                setupOffer.className += ' disabled';
                setupOffer.innerHTML = 'Please wait a few seconds.';

                // start broadcasting userid
                peerConnection.startBroadcasting();
            };

            // --------------------------------------------------------
            var SIGNALING_URI = 'wss://websocket-over-nodejs.herokuapp.com:443/';

            var channel = location.href.replace( /\/|:|#|%|\.|\[|\]/g , '');
            var websocket = new WebSocket(SIGNALING_URI);
            websocket.onopen = function() {
                console.log('websocket connection opened!');
                websocket.push(JSON.stringify({
                    open: true,
                    channel: channel
                }));
            };
            websocket.push = websocket.send;
            websocket.send = function(data) {
                if (websocket.readyState != 1) {
                    console.warn('websocket connection is not opened yet.');
                    return setTimeout(function() {
                        websocket.send(data);
                    }, 1000);
                }

                websocket.push(JSON.stringify({
                    data: data,
                    channel: channel
                }));
            };

            // --------------------------------------------------------
            var peerConnection = new PeerConnection(websocket);

            var usersList = document.getElementById('users-list');

            /*
            peerConnection.onuserfound = function(userid) {
            var li = document.createElement('li');
            li.innerHTML = '<span style="color:red;">' + userid + ' is online</span>. <span class="button">Join</span>';
            usersList.insertBefore(li, usersList.firstChild);
            li.querySelector('.button').onclick = function() {
            usersList.innerHTML = '';
            peerConnection.sendParticipationRequest(userid);
            };
            };
            */

            peerConnection.ondata = function(data) {
                receiver.receive(data);
            };

            peerConnection.onopen = function() {
                innerHTML = '<span>PeerConnection</span> <span>is established.</span>';
                setupOffer.innerHTML = innerHTML;
                setupOffer.style.color = 'green';
                if (setupOffer.className.indexOf('disabled') != -1) setupOffer.className += ' disabled';

                document.querySelector('input[type=file]').disabled = false;
            };

            peerConnection.onclose = function() {
                onCloseOrOnError('<span>PeerConnection</span> <span>is closed.</span>');
            };

            peerConnection.onerror = function() {
                onCloseOrOnError('<span>Something</span> <span>went wrong.</span>');
            };

            function onCloseOrOnError(_innerHTML) {
                innerHTML = _innerHTML;
                setupOffer.innerHTML = innerHTML;
                setupOffer.style.color = 'red';
                setupOffer.className = 'button';

                setTimeout(function() {
                    innerHTML = '<span>Setup</span> <span>WebRTC Connection</span>';
                    setupOffer.innerHTML = innerHTML;
                    setupOffer.style.color = '';
                }, 1000);

                document.querySelector('input[type=file]').disabled = true;
            }

            var uniqueToken = document.getElementById('unique-token');
            if (uniqueToken)
                if (location.hash.length > 2)
                    uniqueToken.parentNode.parentNode.parentNode.innerHTML = '<h2 style="text-align: center;background: rgba(0, 0, 0, .3);border: 1px solid #666;padding: 10px;padding-bottom: 0;box-shadow: inset 0 2px 2px #111;">Your Private Room: <a href="' + location.href + '" target="_blank" style="color: #6792cc;">#'+ location.href.split('#')[1] + '</a></h2>';
                else
                    uniqueToken.innerHTML = uniqueToken.parentNode.parentNode.href = '#' + (Math.round(Math.random() * 999999999) + 999999999);
        </script>
    </body>
</html>
